/*==============================================================================
            Copyright (c) 2013 Moritz Hader, Marcel Schrder
            All Rights Reserved.

	@file  HeimdallNativeMesh.h

	@brief This header provides the class-definitions of the HeimdallNativeMesh.
	It provides the counter-part to the java mesh-class and capsulates the
	vertex and normal fields passed to the vertex-managementunit.
   
   This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
==============================================================================*/

#include <engine/HeimdallNativeMesh.h>
#include <egl/VertexManagementUnit.h>
#include <egl/HeimdallGLUtilities.h>

HeimdallNativeMesh::HeimdallNativeMesh(){
	this->meshType = -1;
}

HeimdallNativeMesh::~HeimdallNativeMesh(){
	if(this->vmuHandle != NULL){
		delete this->vmuHandle;
	}
}

void HeimdallNativeMesh::loadVMU(VertexManagementUnit* vmu){
	this->vmuHandle = vmu;
}

void HeimdallNativeMesh::loadJavaObject(JNIEnv* env, jobject nativeObj){

	__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loading HeimdallNativeMesh into its native counterpart.");

	//Handle to the Heimdall3DObject-Class
	jclass hdClass = env->GetObjectClass(nativeObj);

		if (hdClass == NULL){
			__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Error, could not load the HeimdallNativeMesh-Object java-class into the ndk-environment.");
			return;
		}

	//Get the mesh type (Stock) that is to be loaded
	jmethodID getMeshInteger = env->GetMethodID(hdClass, "getMeshInteger", "()I");

		if(getMeshInteger == 0){
			__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "Error, method getMeshInteger not found");
			return;
		}

		this->meshType = env->CallIntMethod(nativeObj, getMeshInteger);

		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "MeshType %d", this->meshType);

		this->loadMesh();
}


void HeimdallNativeMesh::loadMesh(){

		switch (this->meshType){

		case DEFAULT_CUBE:
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loading Stock Mesh Cube");
			GenSimpleCube(&this->vmuHandle, 10.0f); //Standard-size 10x10x10
			break;

		case DEFAULT_GRID:
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loading Stock Mesh Grid");
			GenSimpleGrid(&this->vmuHandle, 100.0f, 10.0f); //Standard-size 100x100 with gaps of 10
			break;

		case DEFAULT_CONE:
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loading Stock Mesh Cone");
			GenSimpleCone(&this->vmuHandle); //Standard-size 100x100 with gaps of 10
			break;

		case DEFAULT_BARRIER:
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loading Stock Mesh Barrier");
			GenSimpleBarrier(&this->vmuHandle); //Standard-size 100x100 with gaps of 10
			break;

		case DEFAULT_TRAFFICL:
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loading Stock Mesh Traffic-Light");
			GenSimpleTrafficL(&this->vmuHandle); //Standard-size 100x100 with gaps of 10
			break;
		case DEFAULT_FANCYCAR:
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Loading Stock Mesh Fancy-Car");
			GenSimpleFancyCar(&this->vmuHandle); //Standard-size 100x100 with gaps of 10
			break;

		case NONE:
			__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "None");
			break;
		}
}

void HeimdallNativeMesh::finalize(){
	if(this->vmuHandle != NULL){
		this->vmuHandle->Finalize();
	}
}

void HeimdallNativeMesh::draw(){
	this->vmuHandle->Draw();
}

int HeimdallNativeMesh::getMeshType(){
	return this->meshType;
}

/*JNIEXPORT int JNICALL
		Java_de_ibm_dhbw_heimdall_engine_HeimdallMesh_makeVertexCounterpart(JNIEnv *env, jobject obj, int count, int id){

	    	__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Creating mesh-vertex counterpart");

	    	//Get Handle to Class
	    	jclass meshClass = env->GetObjectClass(obj);

	    	if (meshClass == NULL){
	    		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Error, could not load the java-class into the ndk-environment.");
	    	}

	    	//Get Handle to Method (No parameter, returntype float array)
	    	jmethodID getVertexData = env->GetMethodID(meshClass,"getVertexData","()[F");
	    	jmethodID getNormalData = env->GetMethodID(meshClass,"getNormalData","()[F");
	    	jmethodID isNormalData = env->GetMethodID(meshClass,"isNormalSet","()Z");

	    	if (getVertexData == NULL){
	    		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Error, could not load the java-method-handle into the ndk-environment.");
	    	}

	    	//Get the jfloatArrayObject from the method-call
	    	jfloatArray verticesJFA = (jfloatArray)env->CallObjectMethod(obj, getVertexData);
	    	jfloatArray normalsJFA = (jfloatArray)env->CallObjectMethod(obj, getNormalData);
	    	jboolean isNormal= (jboolean)env->CallBooleanMethod(obj, isNormalData);

	    	if (verticesJFA == NULL){
	    		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Error, could not load the vertex-array into the ndk-jfloatArray.");
	    	}

	    		//jfloatArray only capsulates the result of the method-call, thus we need to get a handle to the actual memory
	    		jfloat* verticeHandle = env->GetFloatArrayElements(verticesJFA, NULL);
	    			float* vertices = (float*) verticeHandle;

	    		jfloat* normalHandle = env->GetFloatArrayElements(normalsJFA, NULL);
	    			float* normals = (float*) normalHandle;

		    	if (verticeHandle == NULL){
		    		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Error, could not load the handle to the first element of the jfloatAttay into the ndk-environment.");
		    	}

		    	vertexMUShaded = new VertexManagementUnit(GL_TRIANGLES,count);
		    	//so how do I get the shit over now??? Lets try passing it chunk by chunk

		    	for(int i = 0;i<count;i+=3){
			    	//We use the handle and pass it in as the first element of the float array
		    		H3DVector v,n;

		    		v[0] = vertices[i]; v[1] = vertices[i+1]; v[2] = vertices[i+2];
		    		//vertexMUShaded->AddVertex(verticeHandle+i); //AddVertex expects a H3DVector-Type, which is simply float[3] - I Dont like this style, its shaggy...
		    		vertexMUShaded->AddVertex(v);



		    		if(isNormal){
		    			n[0] = normals[i]; n[1] = normals[i+1]; n[2] = normals[i+2];
		    			//vertexMUShaded->AddNormal(normalHandle+i);
		    			vertexMUShaded->AddNormal(n);

		    		}
		    	}

		    	env->ReleaseFloatArrayElements(verticesJFA, verticeHandle, 0);
		    	env->ReleaseFloatArrayElements(normalsJFA, normalHandle, 0);

	    	return 1;
		}

	JNIEXPORT int JNICALL
			Java_de_ibm_dhbw_heimdall_engine_HeimdallMesh_makeVertexCounterpartAlt(JNIEnv *env, jobject obj, int count, jfloatArray verticesJFA, jfloatArray normalsJFA, int id){

		    	__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Creating mesh-vertex counterpart");



		    	//Get the jfloatArrayObject from the method-call


		    		//jfloatArray only capsulates the result of the method-call, thus we need to get a handle to the actual memory
		    		jfloat* verticeHandle = env->GetFloatArrayElements(verticesJFA, NULL);
		    			float* vertices = (float*) verticeHandle;

		    		jfloat* normalHandle = env->GetFloatArrayElements(normalsJFA, NULL);
		    			float* normals = (float*) normalHandle;

			    	if (verticeHandle == NULL){
			    		__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "Error, could not load the handle to the first element of the jfloatAttay into the ndk-environment.");
			    	}

			    	vertexMUShaded = new VertexManagementUnit(GL_TRIANGLES,count);
			    	//so how do I get the shit over now??? Lets try passing it chunk by chunk

			    	for(int i = 0;i<count;i+=3){
				    	//We use the handle and pass it in as the first element of the float array
			    		H3DVector v,n;

			    		v[0] = vertices[i]; v[1] = vertices[i+1]; v[2] = vertices[i+2];
			    		//vertexMUShaded->AddVertex(verticeHandle+i); //AddVertex expects a H3DVector-Type, which is simply float[3] - I Dont like this style, its shaggy...
			    		vertexMUShaded->AddVertex(v);




			    			n[0] = normals[i]; n[1] = normals[i+1]; n[2] = normals[i+2];
			    			//vertexMUShaded->AddNormal(normalHandle+i);
			    			vertexMUShaded->AddNormal(n);


			    	}

			    	env->ReleaseFloatArrayElements(verticesJFA, verticeHandle, 0);
			    	env->ReleaseFloatArrayElements(normalsJFA, normalHandle, 0);

		    	return 1;
			}*/
